#include "camera.h"
#include <GLFW/glfw3.h>
#include <glm/ext/matrix_float4x4.hpp>
#include <glm/ext/matrix_transform.hpp>
#include <glm/ext/vector_float3.hpp>
#include <glm/geometric.hpp>
#include <glm/trigonometric.hpp>

camera::camera(){
    this->lastx = 0.0f;
    this->lasty = 0.0f;
    this->cameraSpeed = 0.05f;
    this->direction = glm::vec3(0.0f, 0.0f, 0.0f);
    this->position = glm::vec3(0.0f, 0.0f, 3.0f);
    this->updateCameraCoord();
}

camera::camera(const glm::vec3 &pos){
    this->lastx = 0.0f;
    this->lasty = 0.0f;
    this->position = pos;
    this->direction = glm::vec3(0.0f, 0.0f, 0.0f);
    this->right = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f),this->direction));
    this->up = glm::cross(this->direction, this->right);
    this->view = glm::lookAt(this->position, this->position-this->direction, this->up);
}

const glm::vec3 camera::getPosition() const{
    return this->position;
}
const glm::vec3 camera::getDirection() const{
    return this->direction;
}

void camera::setPos(const glm::vec3 &pos){
    this->position = pos;
}

const glm::mat4 camera::getView()const{
    return this->view;
}

void camera::setView(const glm::mat4 &vi) {
    this->view = vi;
}

const float &camera::getCamSp() const{
    return this->cameraSpeed;
}

void camera::setCamSp(const float &camSp) {
    this->cameraSpeed = camSp;
}

const glm::vec3 &camera::getUp() const {
    return this-> up;
}

void camera::setUp(const glm::vec3 &up){
    this->up = up;
}

void camera::setDirection(const glm::vec3 &dir){
    this->direction = dir;
}

const float &camera::getSensitivity()const{
    return sensitivity;
}
void camera::setSensitivity(const float& sen){
    this->sensitivity = sen;
}


void camera::updateCameraCoord(){
    this->right = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f),              this->direction));
    this->up = glm::cross(this->direction, this->right);
    this->view = glm::lookAt(this->position, this->position-this->direction, this->up);
}

void camera::do_movement(){
    float deltaTime = 0.0f;
    float lastFrame = 0.0f;
    float currentFrame = glfwGetTime();
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;
    this->setCamSp(0.05f * deltaTime);

    if(keys[GLFW_KEY_W]){
        this->setPos(glm::vec3(this->getPosition() + (this->getCamSp() * this->           getDirection())));
    }
    else if(keys[GLFW_KEY_S]){
        this->setPos(glm::vec3(this->getPosition() - (this->getCamSp() * this->           getDirection())));
    }
    else if(keys[GLFW_KEY_A]){
        this->setPos(this->getPosition() - (glm::normalize(glm::cross(                    this->getDirection(), this->getUp()))));
    }
    else if(keys[GLFW_KEY_D]){
        this->setPos(this->getPosition() + (glm::normalize(glm::cross(                    this->getDirection(), this->getUp()))));
    }

}

void camera::mouseInput(GLFWwindow *window) const{
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}

const float &camera::getPitch()const{
    return this->pitch;
}

const float &camera::getYaw()const{
    return this->yaw;
}

const float &camera::getRoll()const{
    return this->roll;
}

void camera::setPitch(const float &p){
    this->pitch = p;
}

void camera::setYaw(const float &y){
    this->yaw= y;
}

void camera::setRoll(const float &r){
    this->roll= r;
}

void camera::setDirectionCoords(const float &x, const float &y, const float &z){
    this->direction.x = x;;
    this->direction.y = y;
    this->direction.z = z;
}

const float &camera::getLastx() const {
    return this->lastx;
}

const float &camera::getLasty() const {
    return this->lasty;
}

void camera::setLastx(const float &lastx) {
    this->lastx = lastx;
}

void camera::setLasty(const float &lasty) {
    this->lasty = lasty;
}

